﻿using System;
using System.Data.Common;
using System.Transactions;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.Unity.InterceptionExtension;

namespace TSharp.Core.Aop.Handler
{
    /// <summary>
    /// 事务处理类
    /// </summary>
    public class TransactionHandler : ICallHandler
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="TransactionHandler"/> class.
        /// </summary>
        /// <param name="dataBaseName">Name of the data base.</param>
        /// <param name="isDistributed">if set to <c>true</c> [is distributed].</param>
        /// <param name="order">The order.</param>
        public TransactionHandler(string dataBaseName, bool isDistributed, int order)
        {
            DataBaseName = dataBaseName;
            IsDistributed = isDistributed;
            Order = order;
        }

        /// <summary>
        /// 数据库名称
        /// </summary>
        public string DataBaseName { get; set; }

        /// <summary>
        /// 分布式事务（独立数据库）
        /// </summary>
        public bool IsDistributed { get; set; }

        #region ICallHandler Members

        /// <summary>
        /// Order in which the handler will be executed
        /// </summary>
        /// <value></value>
        public int Order { get; set; }

        /// <summary>
        /// Implement this method to execute your handler processing.
        /// </summary>
        /// <param name="input">Inputs to the current call to the target.</param>
        /// <param name="getNext">Delegate to execute to get the next delegate in the handler
        /// chain.</param>
        /// <returns>Return value from the target.</returns>
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            if (IsDistributed)
            {
                using (var ts = new TransactionScope())
                {
                    IMethodReturn result = getNext()(input, getNext);
                    ts.Complete();
                    return result;
                }
            }
            else
            {
                Database db;
                if (string.IsNullOrEmpty(DataBaseName))
                    db = DatabaseFactory.CreateDatabase();
                else
                    db = DatabaseFactory.CreateDatabase(DataBaseName);
                using (DbConnection connection = db.CreateConnection())
                {
                    connection.Open();
                    DbTransaction transaction = connection.BeginTransaction();
                    try
                    {
                        IMethodReturn result = getNext()(input, getNext);
                        transaction.Commit();
                        return result;
                    }
                    catch (Exception ex)
                    {
                        transaction.Rollback();
                        throw ex;
                    }
                    finally
                    {
                        connection.Close();
                    }
                }
            }
        }

        #endregion
    }
}